﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

using CT = Antlr.Runtime.Tree.CommonTree;

namespace GodPl.Parser
{
    public static class GodPlConverter
    {

        static readonly string header = @"
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using GodPl;
        using GodPl.WorldState;
        using GodPl.GameObjects;
        using Microsoft.Xna.Framework;
        using Microsoft.Xna.Framework.Graphics;

        namespace GodPl.GameObjects.Creatures
        {
            public class UserBriyyaUpdater : IBriyyaUpdater
            {

                private Briyya actor;
                public Briyya Actor
                {
                    get { return actor; }
                }


                public Briyya me
                {
                    get { return actor; }
                }

                public void SetActor(Briyya actor)
                {
                    this.actor = actor;
                }

                public World World
                {
                    get { return actor.World; }
                }

                public void print(string str)
                {
                    GodPlGame.LogLine(str);
                }

                public void print(Object o)
                {
                    GodPlGame.LogLine(o.ToString());
                }
";


        static readonly string triggersHeader = @"
        public void Update(GameTime gameTime)
        {
";


        static readonly string triggersFooter = @"
        }
";

        static readonly string footer = @"
            }
        }
";


        static Dictionary<string, int> tokens = new Dictionary<string, int>();

        public static void InitializeTokens()
        {

        }

        public static string ConvertFromFile(string filename)
        {
            string input;
            System.IO.StreamReader file = new System.IO.StreamReader(filename);
            input = file.ReadToEnd();
            file.Close();

            return Convert(input);
        }


        public static void WriteToFile(string filename, string output)
        {
            System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
            file.Write(output);
            file.Close();
        }

        public static string body = "";

        public static string Convert(string input)
        {

            ANTLRStringStream sStream = new ANTLRStringStream(input);
            GodPlGrammarLexer lexer = new GodPlGrammarLexer(sStream);
            
            CommonTokenStream tStream = new CommonTokenStream(lexer);

            GodPlGrammarParser parser = new GodPlGrammarParser(tStream);
            GodPlGrammarParser.program_return parserResult = parser.program();

            CommonTree ast = (CommonTree)parserResult.Tree;

            Print(ast);
            string output = header + body + footer;

            return output;
        }

        public static void PrintChild(CT ast, int i)
        {
            var c = ast.Children[i];
            CT d = (CT)c;
            Print(d);
        }

        public static void PrintChildren(CT ast)
        {
            PrintChildren(ast, " ", true);
        }

        public static void PrintChildren(CT ast, string delim, bool final)
        {
            if (ast.Children == null)
            {
                return;
            }
            
            int num = ast.Children.Count;

            for (int i = 0; i < num; ++i)
            {
                CT d = (CT)(ast.Children[i]);
                Print(d);
                if (final || i < num - 1)
                {
                    body += delim;
                }
            }
        }

        public static void Print(CommonTree ast)
        {
            switch (ast.Token.Text)
            {
                case "PROGRAM":
                    //body += header;
                    PrintChildren(ast);
                    //body += footer;
                    break;
                case "GLOBALS":
                    body += "\r\n\r\n// GLOBALS\r\n";
                    PrintChildren(ast);
                    break;
                case "GLOBAL":
                    body += "public static ";
                    PrintChildren(ast);
                    body += ";\r\n";
                    break;
                case "INSTANCES":
                    body += "// INSTANCE VARIABLES\r\n";
                    PrintChildren(ast);
                    break;
                case "INSTANCE":
                    body += "public ";
                    PrintChildren(ast);
                    body += ";\r\n";
                    break;
                case "FUNCTIONS":
                    body += "\r\n\r\n// FUNCTIONS\r\n";
                    PrintChildren(ast);
                    break;
                case "FUNCTION":
                    body += "public ";
                    PrintChildren(ast);
                    break;
                case "DECLARATION":
                    PrintChildren(ast);
                    break;
                case "CODE":
                    body += "{\r\n";
                    PrintChildren(ast, ";\r\n", true);
                    body += "}\r\n";
                    break;
                case "PARAMS":
                case "ARGS":
                    body += "(";
                    PrintChildren(ast, ", ", false);
                    body += ")";
                    break;
                case "UNARYMINUS":
                    body += "-";
                    PrintChildren(ast);
                    break;
                case "NOT":
                    body += "!";
                    PrintChildren(ast);
                    break;
                case "ARRAYACCESS":
                    body += "[";
                    PrintChildren(ast);
                    body += "]";
                    break;
                case "FUNCTIONACCESS":
                    PrintChildren(ast);
                    break;
                case "FIELDACCESS":
                    PrintChildren(ast);
                    break;
                case "EVENTS":
                    body += "\r\n\r\n//EVENTS\r\n";
                    body += triggersHeader;
                    PrintChildren(ast);
                    body += triggersFooter;
                    break;
                case "EVENT":
                    body += "if (";
                    PrintChild(ast, 0);
                    body += ") \r\n";
                    PrintChild(ast, 1);
                    break;
                case "ACTIONS":
                    body += "{\r\n";
                    PrintChildren(ast, ";\r\n", true);
                    body += "}\r\n";
                    break;
                case "NAME":
                    PrintChildren(ast);
                    break;
                case "TIMECOMP":
                    body += "(gameTime.TotalGameTime " + ((CT)ast.Children[0]).Text + " ";
                    PrintChild(ast, 1);
                    body += ")";
                    break;
                case "TIMELIT":
                    body += "(GodPlGame.ParseTimeLiteral(\"";
                    PrintChildren(ast);
                    body += "\"))";
                    break;
                case "PARENTHESIZED":
                    body += "(";
                    PrintChildren(ast);
                    body += ")";
                    break;
                case "CONDITIONAL":
                    PrintChildren(ast, "\r\n", true);
                    break;
                case "ASSIGN":
                case "=":
                case "PLUS":
                case "+":
                case "MINUS":
                case "-":
                case "TIMES":
                case "*":
                case "DIVIDE":
                case "/":
                case "MOD":
                case "%":
                case "LESS":
                case "<":
                case "GREATER":
                case ">":
                case "EQUAL":
                case "==":
                case "UNEQUAL":
                case "!=":
                case "LEQUAL":
                case "<=":
                case "GEQUAL":
                case ">=":
                case "OR":
                case "||":
                case "AND":
                case "&&":
                case "DOT":
                case ".":
                    PrintChild(ast, 0);
                    body += ast.Text;
                    PrintChild(ast, 1);
                    break;
                //case "ME":
                //case "me":
                //    body += "this.actor";
                //    break;
                case "EVERY":
                case "every":
                    body += "GodPlGame.Every(";
                    PrintChildren(ast);
                    body += ")";
                    break;
                case "ROLL":
                case "roll":
                    body += "GodPlGame.Roll(";
                    PrintChildren(ast);
                    body += ")";
                    break;
                case "PICKRANDOM":
                case "pickRandom":
                    // Insert a down-cast
                    body += "GodPlGame.PickRandom<";
                    PrintChildren(ast);
                    body += ">()";
                    break;
                case "NUMERICLIT":
                    body += " ";
                    PrintChildren(ast,"",false);
                    body += "f ";
                    break;
                case "NumericLiteral":
                case "DecimalLiteral":
                    body += ast.Text;
                    body += "f";
                    break;
                case "'if'":
                case "if":
                case "'else if'":
                case "else if":
                case "'while'":
                case "while":
                    body += ast.Text + "(";
                    PrintChild(ast, 0);
                    body += ")\r\n";
                    PrintChild(ast, 1);
                    break;
                case "'else'":
                case "else":
                    body += ast.Text;
                    PrintChildren(ast);
                    break;
                case "'return'":
                case "return":
                    body += "return ";
                    PrintChildren(ast);
                    break;
                case "'foreach'":
                case "foreach":
                    body += "foreach (";
                    PrintChild(ast, 0);
                    body += " ";
                    PrintChild(ast, 1);
                    body += " in GodPlGame.GetAllOf<";
                    PrintChild(ast, 0);
                    body += ">())\r\n";
                    PrintChild(ast, 2);
                    break;







                default:
                    body += ast.Text;
                    break;

            }
        }
    }
}
